package com.bestv.search.management.servlet;

import com.bestv.search.common.cache.SystemCache;
import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.SysRole;
import com.bestv.search.common.model.SysUser;
import com.bestv.search.common.service.SysUserManager;
import com.bestv.search.management.command.AccessLogCommand;
import com.bestv.search.management.command.UserStatusCommand;
import org.apache.log4j.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartRenderingInfo;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.entity.StandardEntityCollection;
import org.jfree.chart.labels.*;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot3D;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.servlet.ServletUtilities;
import org.jfree.chart.title.LegendTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.general.Dataset;
import org.jfree.data.general.PieDataset;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.RectangleInsets;
import org.jfree.ui.TextAnchor;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

public final class BuildChartServlet extends HttpServlet implements Servlet {
    private static final long serialVersionUID = -8278244255880544597L;
    private static final String DO_HIT = "doHit";
    private static final String DO_HIT_TOP_SUGGEST_SEARCH = "doHitTopSuggestSearch";
    private static final String NEW_USER_COUNT = "newUserCount";
    private static final String USER_STATUS_COUNT = "userStatusCount";
    private static final String LINE_CHART = "line";
    private static final String BAR_CHART = "bar";
    private static final String PIE_CHART = "pie";
    private static final String FONT_TYPE = "Dialog";
    private static final String NO_DATA_MESSAGE = "无任何数据";
    private Logger logger = Logger.getLogger(BuildChartServlet.class);
    private WebApplicationContext wac;
    private AccessLogCommand accesslogCmd;
    private SysUserManager userManager;
    private UserStatusCommand userStatus;
    private SystemCache systemCache;

    // Creates chart by dataset.
    public static JFreeChart createChart(Dataset dataset, String title, String categoryAxisLabel,
                                         String ValueAxisLabel, String chartName, String chartType) throws IOException {

        // Creates chart
        JFreeChart chart = null;
        if (chartType.equals(LINE_CHART)) {
            // line chart
            chart = ChartFactory.createLineChart(title, categoryAxisLabel, ValueAxisLabel, (CategoryDataset) dataset,
                    PlotOrientation.VERTICAL, true, true, false);
        } else if (chartType.equals(BAR_CHART)) {
            // Bar chart
            chart = ChartFactory.createBarChart3D(title, categoryAxisLabel, ValueAxisLabel, (CategoryDataset) dataset,
                    PlotOrientation.VERTICAL, true, true, false);
        } else {
            // Pie chart
            chart = ChartFactory.createPieChart3D(title, (PieDataset) dataset, true, true, Locale.CHINA);
        }

        // Sets font to title.
        Font font_Title = new Font(FONT_TYPE, Font.BOLD, 16);
        chart.getTitle().setFont(font_Title);
        chart.getTitle().setMargin(0, 0, 5, 0);

        if (chartType.equals(PIE_CHART)) {
            PiePlot3D plot = (PiePlot3D) chart.getPlot();

            plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{1}"));

            // Sets format to "legend" axis
            LegendTitle legend = chart.getLegend();
            legend.setItemFont(new Font(FONT_TYPE, Font.BOLD, 12));
            legend.setItemLabelPadding(new RectangleInsets(1, 1, 2, 1));
            legend.setPosition(RectangleEdge.TOP);
            legend.setBackgroundPaint(Color.lightGray);

            // Sets format to "Item" axis
            plot.setNoDataMessage(NO_DATA_MESSAGE);
            plot.setNoDataMessageFont(new Font(FONT_TYPE, Font.BOLD, 12));
            plot.setBackgroundPaint(Color.white);
            plot.setOutlinePaint(Color.white);
            if (chartName.equals(DO_HIT) || chartName.equals(DO_HIT_TOP_SUGGEST_SEARCH)) {
                plot.setToolTipGenerator(new AccessLogCommand.AccessLogPieToolTipGenerator());
            } else {
                plot.setToolTipGenerator(new StandardPieToolTipGenerator());
            }
        } else {
            // Sets format to "x" axis
            CategoryPlot plot = (CategoryPlot) chart.getPlot();
            plot.setNoDataMessage(NO_DATA_MESSAGE);
            plot.setNoDataMessageFont(new Font(FONT_TYPE, Font.BOLD, 12));
            CategoryAxis domainAxis = plot.getDomainAxis();
            domainAxis.setTickLabelFont(new Font(FONT_TYPE, Font.BOLD, 12));
            domainAxis.setLabelFont(new Font(FONT_TYPE, Font.BOLD, 14));
            domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);

            // Sets format to "y" axis
            ValueAxis valueAxis = plot.getRangeAxis();
            valueAxis.setLabelFont(new Font(FONT_TYPE, Font.BOLD, 14));
            valueAxis.setAutoRange(true);
            valueAxis.setLowerBound(0);
            valueAxis.setAutoRangeMinimumSize(20000);
            valueAxis.setUpperMargin(0.1);

            // Sets format to "legend" axis
            LegendTitle legend = chart.getLegend();
            legend.setItemFont(new Font(FONT_TYPE, Font.BOLD, 12));
            legend.setItemLabelPadding(new RectangleInsets(1, 1, 1, 1));
            legend.setPosition(RectangleEdge.TOP);
            legend.setBackgroundPaint(Color.lightGray);

            // Sets format to "Item" axis
            CategoryItemRenderer renderer = plot.getRenderer();
            renderer.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
            renderer.setBaseItemLabelFont((new Font(FONT_TYPE, Font.PLAIN, 12)));
            renderer.setBaseItemLabelsVisible(true);

            // Sets color to each series.
            int seriesCount = renderer.getLegendItems().getItemCount();
            if (seriesCount == 4) {
                renderer.setSeriesPaint(0, Color.red);
                renderer.setSeriesPaint(1, Color.blue);
                renderer.setSeriesPaint(2, Color.green);
                renderer.setSeriesPaint(3, Color.orange);
            }

            if (chartName.equals(DO_HIT) || chartName.equals(DO_HIT_TOP_SUGGEST_SEARCH)) {
                renderer.setBaseToolTipGenerator(new AccessLogCommand.AccessLogCategoryTooltipGenerator());
            } else {
                renderer.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator());
            }
            // Sets Position of item
            ItemLabelPosition itemLabelPosition = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12,
                    TextAnchor.BASELINE_LEFT);
            renderer.setBasePositiveItemLabelPosition(itemLabelPosition, true);
            renderer.setBaseNegativeItemLabelPosition(itemLabelPosition, true);

            // Sets visible of shape for line chart.
            if (renderer instanceof LineAndShapeRenderer) {
                ((LineAndShapeRenderer) renderer).setBaseShapesVisible(true);
                ((LineAndShapeRenderer) renderer).setBaseShapesFilled(true);
            }

            plot.setRangeGridlinesVisible(true);
            plot.setRangeGridlinePaint(Color.gray);
            plot.setBackgroundPaint(Color.white);
        }
        return chart;
    }

    @Override
    public void init() throws ServletException {
        wac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
        accesslogCmd = (AccessLogCommand) wac.getBean("accessLogCommand");
        userManager = (SysUserManager) wac.getBean("userManager");
        systemCache = (SystemCache) wac.getBean("systemCache");
        userStatus = (UserStatusCommand) wac.getBean("userStatusCommand");
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doExecute(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {
        doExecute(request, response);
    }

    @SuppressWarnings("unchecked")
    private void doExecute(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        String toolTipId = "";
        String chartName = request.getParameter("chartName");
        String chartType = request.getParameter("chartType");

        // Gets data Source key
        String dataSourceKey = (String) request.getSession().getAttribute("dataSourceKey");
        DataSourceKey dsKey = DataSourceKeyUtil.convert(dataSourceKey);

        String loginName = (String) request.getSession().getAttribute("ACEGI_SECURITY_LAST_USERNAME");
        if (loginName == null || "".equals(loginName)) {
            response.getWriter().write("Error: Not login");
            return;
        } else {
            SysUser user = userManager.getUserByLoginName(dsKey, loginName);
            // If isn't HDQ user, just can access the site that user belong to,
            if (user != null) {
                if (user.getSite().getCode() != null) {
                    // Check Permission
                    Set<SysRole> roles = user.getRoles();
                    boolean permissionFlag = false;
                    for (SysRole role : roles) {
                        if (role != null
                                && (role.getName().equals(systemCache.getLocalDataSourceKey()) || role.getName()
                                .equals("HDQ"))) {
                            permissionFlag = true;
                            break;
                        }
                    }

                    // don have Permission
                    if (!permissionFlag) {
                        response.getWriter().write("No Permission");
                        return;
                    }
                }
            }

            // Gets Dataset.
            Dataset dataset = null;
            try {
                Map<String, Dataset> dataSetMap = null;
                if (chartName.equals(DO_HIT) || chartName.equals(DO_HIT_TOP_SUGGEST_SEARCH)) {
                    dataSetMap = accesslogCmd.getChartDatasetAndToolTipId(user, request.getParameterMap(), dsKey);
                } else if (chartName.equals(NEW_USER_COUNT)) {
                    dataSetMap = userStatus.getChartDatasetAndToolTipIdForNewUserCount(user, request.getParameterMap(),
                            dsKey);
                } else if (chartName.equals(USER_STATUS_COUNT)) {
                    dataSetMap = userStatus.getChartDatasetAndToolTipIdForUserStatusCount(user,
                            request.getParameterMap(), dsKey);
                }
                if (dataSetMap == null) {
                    logger.error("Parameters is not correctly");
                    response.getWriter().write("Error: Parameters incorrectly");
                    return;
                } else {
                    toolTipId = dataSetMap.keySet().toArray()[0].toString();
                    dataset = dataSetMap.get(toolTipId);
                }
            } catch (Exception e) {
                logger.error("Exception happened,  " + e);
                e.printStackTrace();
                response.getWriter().write("Error: Site interface incorrectly");
                return;
            }

            // Gets chart
            JFreeChart chart = createChart(dataset, getChartTitle(chartName), "", "", chartName, chartType);

            // Map info
            StandardEntityCollection sec = new StandardEntityCollection();
            ChartRenderingInfo info = new ChartRenderingInfo(sec);

            String fileName = ServletUtilities.saveChartAsPNG(chart, 900, 450, info, request.getSession());
            ChartUtilities.writeImageMap(response.getWriter(), toolTipId, info, false);

            String imgSrc = request.getContextPath() + "/DisplayChart?filename=" + fileName;
            response.getWriter().write(imgSrc);
        }
    }

    private String getChartTitle(String chartName) {
        if (chartName.equals(DO_HIT)) {
            return "有效搜索请求统计";
        } else if (chartName.equals(DO_HIT_TOP_SUGGEST_SEARCH)) {
            return "所有请求统计 ";
        } else if (chartName.equals(NEW_USER_COUNT)) {
            return "新增用户统计 ";
        } else if (chartName.equals(USER_STATUS_COUNT)) {
            return "用户状态统计 ";
        }
        return "";
    }
}
